home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 476-500 / disk_494 / vscreen / source / vscreensetup.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  14KB  |  471 lines

  1. /*
  2.  *  VSCREENSETUP.C  Creates virtual screens that can be larger than
  3.  *                  the actual display area of your monitor.  The virtual
  4.  *                  screen scrolls when the mouse moves off the edge of
  5.  *                  the display.
  6.  *
  7.  *                  Copyright 1988 by Davide P. Cervone, all rights reserved.
  8.  *
  9.  *                  You may may distibute this code as is for non-commercial
  10.  *                  purposes, provided that this notice remains intact and the
  11.  *                  documentation file is distributed with it.
  12.  *
  13.  *                  You may not modify this code or incorporate it into your
  14.  *                  own programs without the permission of the author.
  15.  */
  16.  
  17. /*
  18.  *  WARNING:  This code uses and even modifies the INTUITIONPRIVATE
  19.  *  area of the IntuitionBase structure.  Use it at your own risk.  It is
  20.  *  likely to break under a future release of Intuition.
  21.  */
  22.  
  23. #include "vScreen.h"
  24.  
  25. struct LayersBase *LayersBase = NULL;       /* the Layers Library */
  26.  
  27. extern struct vScreenInfo *vScreenData;     /* the data from the Handler */
  28. extern struct Screen *VScreen;              /* the virtual screen pointer */
  29. extern SHORT ScreenWidth,ScreenHeight;      /* the new width and height */
  30. static UBYTE OldDepth;                      /* the screen depth */
  31.  
  32. extern void CheckLibOpen();
  33. extern void DoExit();
  34.  
  35.  
  36. #define BLT_COPY    0xC0                    /* blitter copy function */
  37. #define MIN(x,y)    (((x)<(y))?(x):(y))     /* MIN macro */
  38.  
  39.  
  40. /*
  41.  *  FindScreen()
  42.  *
  43.  *  If a screen name was specified, look through the Intuition screens
  44.  *  for the first one that matches the specified name (case does not matter),
  45.  *  otherwise, use the active screen.
  46.  *  if the screen was not found, exit with an error message.
  47.  */
  48.  
  49. struct Screen *FindScreen(ScreenName)
  50. char *ScreenName;
  51. {
  52.    struct Screen *theScreen;
  53.  
  54.    Forbid();
  55.    if (ScreenName && ScreenName[0])
  56.    {
  57.       theScreen = IntuitionBase->FirstScreen;
  58.       while (theScreen && (theScreen->Title == NULL ||
  59.              stricmp(theScreen->Title,ScreenName) != 0))
  60.                 theScreen = theScreen->NextScreen;
  61.    } else {
  62.       theScreen = IntuitionBase->ActiveScreen;
  63.    }
  64.    Permit();
  65.    if (theScreen == NULL) DoExit("Can't find screen '%s'",ScreenName);
  66.    return(theScreen);
  67. }
  68.  
  69.  
  70. /*
  71.  *  CheckWindows()
  72.  *
  73.  *  Make sure that all the windows on the virtual screen will fit on the
  74.  *  screen when we reduce it to its original size.
  75.  *
  76.  *  For each window on the screen,
  77.  *    check that its right edge will be on the smaller-sized screen.
  78.  *    if not, move it to the left so that it will be.
  79.  *      if that would move the left egde off the screen, then
  80.  *        shrink the window so that it fits.
  81.  *    Check the the bottom edge will be on the smaller screen.
  82.  *    if no, then move it up so that it will be.
  83.  *      if that would move the top edge off the screen, then
  84.  *         shrink the window so that it fits.
  85.  *    If the window needs to change size or position, do so, and record
  86.  *      the number of changes made.
  87.  *
  88.  *  if any windows were changed, delay long enough for Intuition to update
  89.  *    the windows before we actually restore the screen size.  (This is a
  90.  *    kludge, but I don't know a better method that this.  You may need to
  91.  *    adjust the timing factore for busier screens).
  92.  */
  93.  
  94. static void CheckWindows(theScreen,theWidth,theHeight)
  95. struct Screen *theScreen;
  96. SHORT theWidth,theHeight;
  97. {
  98.    struct Window *theWindow;
  99.    SHORT x,y, w,h;
  100.    SHORT Wx,Wy, Ww,Wh;
  101.    short wChanged = 0;
  102.  
  103.    if (theScreen)
  104.    {
  105.       theWindow = theScreen->FirstWindow;
  106.       while (theWindow)
  107.       {
  108.          Wx = x = theWindow->LeftEdge;
  109.          Wy = y = theWindow->TopEdge;
  110.          Ww = w = theWindow->Width;
  111.          Wh = h = theWindow->Height;
  112.          
  113.          if (x+w > theWidth)
  114.          {
  115.             x = theWidth - w;
  116.             if (x < 0)
  117.             {
  118.                x = 0;
  119.                w = theWidth;
  120.             }
  121.          }
  122.  
  123.          if (y+h > theHeight)
  124.          {
  125.             y = theHeight - h;
  126.             if (y < 0)
  127.             {
  128.                y = 0;
  129.                h = theHeight;
  130.             }
  131.          }
  132.  
  133.          if (x != Wx || y != Wy)
  134.          {
  135.             MoveWindow(theWindow,x-Wx,y-Wy);
  136.             wChanged++;
  137.          }
  138.          
  139.          if (w != Ww || h != Wh)
  140.          {
  141.             SizeWindow(theWindow,w-Ww,h-Wh);
  142.             wChanged++;
  143.          }
  144.  
  145.          theWindow = theWindow->NextWindow;
  146.       }
  147.    }
  148.    if (wChanged) Delay(wChanged * 30L);
  149. }
  150.  
  151.  
  152. /*
  153.  *  GetPlane()
  154.  *
  155.  *  Allocate a bitplane and copy one of the VScren bitplanes into it, then 
  156.  *  free the old bitplane and replace it with the new one.
  157.  *
  158.  *  Two temporary bitmaps are used so that we can call BltBitMap.  The
  159.  *  new bitplane is cleared in case it is larger than the old one, then
  160.  *  the old one is copied.  Since BltBitMap is asynchronous, we call BltClear
  161.  *  on a dummy section of memory to synchronize with the BltBitMap.  That way
  162.  *  we don't free the old raster until it is fully copied.
  163.  *
  164.  *  GetPlane() is used to get the larger bitmap as well as the smaller one 
  165.  *  when we restore the original screen, so MIN() is used to determine
  166.  *  the size of the BltBitMap() action.
  167.  */
  168.  
  169. static int GetPlane(i,Map1,Map2,junk)
  170. int i;
  171. struct BitMap *Map1,*Map2;
  172. UBYTE *junk;
  173. {
  174.    int error = TRUE;
  175.    long w1 = (Map1->BytesPerRow) << 3;
  176.    long h1 = Map1->Rows;
  177.    long w2 = (Map2->BytesPerRow) << 3;
  178.    long h2 = Map2->Rows;
  179.  
  180.    Map2->Planes[0] = VScreen->BitMap.Planes[i];
  181.    Map1->Planes[0] = AllocRaster(w1,h1);
  182.    if (Map1->Planes[0])
  183.    {
  184.       BltClear(Map1->Planes[0],RASSIZE(w1,h1),0L);
  185.       BltBitMap(Map2,0L,0L,Map1,0L,0L,MIN(w1,w2),MIN(h1,h2),BLT_COPY,0xFF,NULL);
  186.       BltClear(junk,8L,0L);  /* synchronize with BltBitMap */
  187.       VScreen->BitMap.Planes[i] = Map1->Planes[0];
  188.       FreeRaster(Map2->Planes[0],w2,h2);
  189.       error = FALSE;
  190.    }
  191.    return(error);
  192. }
  193.  
  194.  
  195. /*
  196.  *  GetBitMap()
  197.  *
  198.  *  GetBitMap allocates and copies a new, larger bitmap for the virtual
  199.  *  screen.  It does so one plane at a time, however, in order avoid having
  200.  *  the complete old screen and the complete new screen in memory at the
  201.  *  same time.  Two temporary bitmaps are used to perform the single-plane
  202.  *  copies.  The junk memory is used to synchronize the BltBitMap calls (see
  203.  *  GetPlane() above).
  204.  *
  205.  *  For each bitplane in the screen, get a new plane of the proper
  206.  *  size.  If the allocation fails, try to clean up (it's usually too
  207.  *  late, however).
  208.  *
  209.  *  Modify the screen's bitmap to reflect the changed size.
  210.  *  Free the junk space.
  211.  */
  212.  
  213. static void GetBitMap()
  214. {
  215.    struct BitMap MyBitMap;
  216.    struct BitMap theBitMap;
  217.    int i;
  218.    UBYTE *junk;
  219.  
  220.    junk = AllocMem(8L,MEMF_CHIP);
  221.    InitBitMap(&MyBitMap,1L,ScreenWidth,ScreenHeight);
  222.    InitBitMap(&theBitMap,1L,VAR(OldWidth),VAR(OldHeight));
  223.    for (i=0; i<OldDepth; i++)
  224.    {
  225.       if (GetPlane(i,&MyBitMap,&theBitMap,junk))
  226.       {
  227.          for(i--; i; i--)
  228.          {
  229.             if (GetPlane(i,&theBitMap,&MyBitMap,junk))
  230.                DoExit("Bail Out!  Serious Trouble Restoring Bit Planes!");
  231.          }
  232.          FreeMem(junk,8L);
  233.          DoExit("Can't Get Memory for Large Bit Planes");
  234.       }
  235.    }
  236.    VScreen->BitMap.BytesPerRow = MyBitMap.BytesPerRow;
  237.    VScreen->BitMap.Rows = MyBitMap.Rows;
  238.    FreeMem(junk,8L);
  239. }
  240.  
  241.  
  242. /*
  243.  *  FreeBitMap()
  244.  *
  245.  *  Similar to GetBitMap, except that FreeBitMap trys to allocate a bitmap
  246.  *  the size of the original screen.
  247.  */
  248.  
  249. static void FreeBitMap()
  250. {
  251.    struct BitMap MyBitMap;
  252.    struct BitMap theBitMap;
  253.    short i;
  254.    UBYTE *junk;
  255.  
  256.    junk = AllocMem(8L,MEMF_CHIP);
  257.    InitBitMap(&MyBitMap,1L,ScreenWidth,ScreenHeight);
  258.    InitBitMap(&theBitMap,1L,VAR(OldWidth),VAR(OldHeight));
  259.    for (i=0; i<OldDepth; i++)
  260.    {
  261.       if (GetPlane(i,&theBitMap,&MyBitMap,junk))
  262.       {
  263.          FreeMem(junk,8L);
  264.          DoExit("Help!  Failed to Restore Bit Planes!");
  265.       }
  266.    }
  267.    VScreen->BitMap.BytesPerRow = theBitMap.BytesPerRow;
  268.    VScreen->BitMap.Rows = theBitMap.Rows;
  269.    FreeMem(junk,8L);
  270. }
  271.  
  272.  
  273. /*
  274.  *  SetClipRects()
  275.  *
  276.  *  Since the screen size is changing, we need to modify the ClipRects
  277.  *  for the menubar's Layer.  This allows the layer to update itself
  278.  *  properly.
  279.  *
  280.  *  Set the menubar bounds-rectangle size.
  281.  *  For each ClipRect in the menubar layer,
  282.  *    If the bounds-rectangle's right edge is at the edge of the old screen
  283.  *      then set it to be the edge of the new screen.
  284.  */
  285.  
  286. static void SetClipRects(OldX,NewX)
  287. WORD OldX,NewX;
  288. {
  289.    struct ClipRect *theClipRect = VScreen->BarLayer->ClipRect;
  290.  
  291.    OldX--; NewX--;
  292.    VScreen->BarLayer->bounds.MaxX = NewX;
  293.    while (theClipRect)
  294.    {
  295.       if (theClipRect->bounds.MaxX == OldX)
  296.          theClipRect->bounds.MaxX = NewX;
  297.       theClipRect = theClipRect->Next; 
  298.    }
  299. }
  300.  
  301.  
  302. /*
  303.  *  EnlargeScreen()
  304.  *
  305.  *  Store the current state of the screen and change what needs to be 
  306.  *  changed in order to make it bigger.
  307.  *
  308.  *  Open the Layers Library so that we can call LockLayers().
  309.  *  Lock the Layers for the screen.  The Forbid() may not be necessary.
  310.  *
  311.  *  Get the HIRES and LACE flags for the screen.  Set up the Shift values
  312.  *  needed to convert the screen's local coordinates to actual display
  313.  *  coordinates (always considered 640 x 400 mode).
  314.  *
  315.  *  Get the pointers to the RxOffset and RyOffset variables of the RasInfo
  316.  *  for the ViewPort of the virtual Screen.  These are what tell the
  317.  *  graphics library which part of the bitmap to display.  These are what
  318.  *  make it possible to scroll the screen quickly and easily.  Without them,
  319.  *  vScreen would be impossible, but luckily, the graphics library knows how
  320.  *  to use them.  Unfortunately, Intuition does not, so we have to bend
  321.  *  over backwards to fool intuition.  See vScreen-Handler.c for details.
  322.  *
  323.  *  Get the old width and height of the screen, and the depth.
  324.  *  Get the new, larger bitplanes for the screen.
  325.  *
  326.  *  Set the screen width and height, and repair the ClipRects in the
  327.  *  menubar Layer.
  328.  *
  329.  *  Get the old MaxDisplay values.
  330.  *
  331.  *  Call the handler's SetVScreen() routine (it sets the MaxDisplay
  332.  *  values, the Max and Min Mouse values, and some other stuff),
  333.  *  and the FixView() routine, which calls MakeVPort() and MrgCop() to
  334.  *  incorporate the screen changes into the Intuition View structure.
  335.  *  Finally, load the new View so taht the larger screen will be displayed.
  336.  *
  337.  *  Unlock the layers and close the library.
  338.  *
  339.  *  Call ShowTitle, so that the menubar layer will be updated (so that
  340.  *  it is as wide as the new screen).
  341.  */
  342.  
  343. void EnlargeScreen()
  344. {
  345.    CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV);
  346.    LockLayers(&(VScreen->LayerInfo));
  347.    Forbid();
  348.  
  349.    VAR(HiResScreen) = (VScreen->ViewPort.Modes & HIRES);
  350.    VAR(LaceScreen)  = (VScreen->ViewPort.Modes & LACE);
  351.    VAR(HiResShift) = (VAR(HiResScreen))? 0: 1;
  352.    VAR(LaceShift)  = (VAR(LaceScreen))? 0: 1;
  353.  
  354.    VAR(RxOffset) = &(VScreen->ViewPort.RasInfo->RxOffset);
  355.    VAR(RyOffset) = &(VScreen->ViewPort.RasInfo->RyOffset);
  356.    VAR(RxOffset2) = (*(VAR(RxOffset))) << VAR(HiResShift);
  357.    VAR(RyOffset2) = (*(VAR(RyOffset))) << VAR(LaceShift);
  358.  
  359.    VAR(OldWidth)  = VScreen->Width;
  360.    VAR(OldHeight) = VScreen->Height;
  361.    OldDepth = VScreen->BitMap.Depth;
  362.    GetBitMap();
  363.  
  364.    VScreen->Width  = ScreenWidth;
  365.    VScreen->Height = ScreenHeight;
  366.    SetClipRects(VAR(OldWidth),ScreenWidth);
  367.  
  368.    VAR(OldMaxDH) = IntuitionBase->MaxDisplayHeight;
  369.    VAR(OldMaxDR) = IntuitionBase->MaxDisplayRow;
  370.    VAR(OldMaxDW) = IntuitionBase->MaxDisplayWidth;
  371.  
  372.    VAR(SetVScreen)();
  373.    VAR(FixView)(TRUE);
  374.    LoadView(&(IntuitionBase->ViewLord));
  375.  
  376.    Permit();
  377.    UnlockLayers(&(VScreen->LayerInfo));
  378.    CloseLibrary(LayersBase); LayersBase = NULL;
  379.  
  380.    ShowTitle(VScreen,(VScreen->Flags & SHOWTITLE)? TRUE: FALSE);
  381. }
  382.  
  383.  
  384. /*
  385.  *  RestoreScreen()
  386.  *
  387.  *  If the screen still exists (i.e.,it was not closed while vScreen was
  388.  *  running), then check the windows to be sure that they all will fit on
  389.  *  the original-sized screen.
  390.  *  Open the Layers Library, and lock the screen layers.
  391.  *  Reset the old screen size, and set the menubar ClipRects to the old size.
  392.  *  Set the offsets to zero, and call the Handler's ResetVScreen() routine
  393.  *  (which resets Intuitions MaxDisplay and Min and Max Mouse fields).
  394.  *  Get the screen depth and restore the old bitmap.
  395.  *  Finally, unlock the screen, and remake the Intuition display so that
  396.  *  the new sized screen is displayed.
  397.  *  update the title bar so that it is the right size.
  398.  */
  399.  
  400. void RestoreScreen()
  401. {
  402.    if (VScreen)
  403.    {
  404.       CheckWindows(VScreen,VAR(OldWidth),VAR(OldHeight));
  405.  
  406.       CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV);
  407.       LockLayers(&(VScreen->LayerInfo));
  408.       Forbid();
  409.  
  410.       VScreen->Width  = VAR(OldWidth);
  411.       VScreen->Height = VAR(OldHeight);
  412.       SetClipRects(ScreenWidth,VAR(OldWidth));
  413.  
  414.       *(VAR(RxOffset)) = 0;
  415.       *(VAR(RyOffset)) = 0;
  416.       VAR(ResetVScreen)();
  417.  
  418.       OldDepth = VScreen->BitMap.Depth;
  419.       FreeBitMap();
  420.  
  421.       Permit();
  422.       UnlockLayers(&(VScreen->LayerInfo));
  423.       CloseLibrary(LayersBase); LayersBase = NULL;
  424.  
  425.       RemakeDisplay();
  426.       ShowTitle(VScreen,(VScreen->Flags & SHOWTITLE)? TRUE: FALSE);
  427.    }
  428. }
  429.  
  430.  
  431. /*
  432.  *  SetVariables()
  433.  *
  434.  *  Store that vScreenData pointer in the MsgPort structure so we can look
  435.  *  it up later (in order to remove the handler).  Save the library pointers
  436.  *  so that the handler can use them, and save the pointer to the virtual 
  437.  *  screen abd its new width and height.
  438.  */
  439.  
  440. void SetVariables(NamedPort)
  441. struct MsgPort *NamedPort;
  442. {
  443.    NamedPort->mp_SigTask = (struct Task *) vScreenData;
  444.    VAR(IntuitionBase) = IntuitionBase;
  445.    VAR(GfxBase)       = GfxBase;
  446.    VAR(VScreen)       = VScreen;
  447.    VAR(ScreenWidth)   = ScreenWidth;
  448.    VAR(ScreenHeight)  = ScreenHeight;
  449. }
  450.  
  451.  
  452. /*
  453.  *  GetVariables()
  454.  *
  455.  *  Retrieve the vScreenData pointer from the MsgPort were we stored it
  456.  *  earlier.  Get back the library pointers so that we can use them and close
  457.  *  them.  Get back the pointer to the virtual screen and its new width
  458.  *  and height.
  459.  */
  460.  
  461. void GetVariables(NamedPort)
  462. struct MsgPort *NamedPort;
  463. {
  464.    vScreenData   = (struct vScreenInfo *) (NamedPort->mp_SigTask);
  465.    IntuitionBase = VAR(IntuitionBase);
  466.    GfxBase       = VAR(GfxBase);
  467.    VScreen       = VAR(VScreen);
  468.    ScreenWidth   = VAR(ScreenWidth);
  469.    ScreenHeight  = VAR(ScreenHeight);
  470. }
  471.